home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / editors / stevie36.4 < prev    next >
Internet Message Format  |  1989-05-12  |  48KB

  1. Path: xanth!nic.MR.NET!umn-d-ub!rutgers!apple!oliveb!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i133:  stevie - vi editor clone v3.6, Part04/06
  5. Message-ID: <104420@sun.Eng.Sun.COM>
  6. Date: 12 May 89 03:07:00 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1878
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: grwalter@watmath.waterloo.edu (Fred Walter)
  12. Posting-number: Volume 89, Issue 133
  13. Archive-name: editors/stevie36.4
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    os2.c
  24. #    os2.h
  25. #    param.c
  26. #    param.h
  27. #    porting.doc
  28. #    regexp.c
  29. # This is archive 4 of a 6-part kit.
  30. # This archive created: Thu May 11 19:41:27 1989
  31. echo "extracting os2.c"
  32. sed 's/^X//' << \SHAR_EOF > os2.c
  33. X/*
  34. X * OS/2 System-dependent routines.
  35. X *
  36. X * $Log:        os2.c,v $
  37. X * Revision 1.2  88/04/25  16:50:19  tony
  38. X * Minor changes for OS/2 version 1.1; also fixed up the RCS header.
  39. X * 
  40. X * Revision 1.1  88/03/21  12:04:23  tony
  41. X * Initial revision
  42. X * 
  43. X *
  44. X */
  45. X
  46. X#define INCL_BASE
  47. X#include <os2.h>
  48. X#include "stevie.h"
  49. X
  50. X/*
  51. X * inchar() - get a character from the keyboard
  52. X */
  53. Xint
  54. Xinchar()
  55. X{
  56. X    int             c;
  57. X
  58. X    for (;; beep()) {        /* loop until we get a valid character */
  59. X
  60. X    flushbuf();        /* flush any pending output */
  61. X
  62. X    switch (c = getch()) {
  63. X      case 0x1e:
  64. X        return K_CGRAVE;
  65. X      case 0:        /* special key */
  66. X      case 0xe0:        /* special key */
  67. X        if (State != NORMAL) {
  68. X        c = getch();    /* throw away next char */
  69. X        continue;    /* and loop for another char */
  70. X        }
  71. X        switch (c = getch()) {
  72. X          case 0x50:
  73. X        return K_DARROW;
  74. X          case 0x48:
  75. X        return K_UARROW;
  76. X          case 0x4b:
  77. X        return K_LARROW;
  78. X          case 0x4d:
  79. X        return K_RARROW;
  80. X          case 0x52:
  81. X        return K_INSERT;
  82. X          case 0x47:
  83. X        stuffReadbuff("1G");
  84. X        return -1;
  85. X          case 0x4f:
  86. X        stuffReadbuff("G");
  87. X        return -1;
  88. X          case 0x51:
  89. X        stuffReadbuff(mkstr(CTRL('F')));
  90. X        return -1;
  91. X          case 0x49:
  92. X        stuffReadbuff(mkstr(CTRL('B')));
  93. X        return -1;
  94. X        /*
  95. X         * Hard-code some useful function key macros. 
  96. X         */
  97. X          case 0x3b:    /* F1 */
  98. X        stuffReadbuff(":p\n");
  99. X        return -1;
  100. X          case 0x54:    /* SF1 */
  101. X        stuffReadbuff(":p!\n");
  102. X        return -1;
  103. X          case 0x3c:    /* F2 */
  104. X        stuffReadbuff(":n\n");
  105. X        return -1;
  106. X          case 0x55:    /* SF2 */
  107. X        stuffReadbuff(":n!\n");
  108. X        return -1;
  109. X          case 0x3d:    /* F3 */
  110. X        stuffReadbuff(":e #\n");
  111. X        return -1;
  112. X          case 0x3e:    /* F4 */
  113. X        stuffReadbuff(":rew\n");
  114. X        return -1;
  115. X          case 0x57:    /* SF4 */
  116. X        stuffReadbuff(":rew!\n");
  117. X        return -1;
  118. X          case 0x3f:    /* F5 */
  119. X        stuffReadbuff("[[");
  120. X        return -1;
  121. X          case 0x40:    /* F6 */
  122. X        stuffReadbuff("]]");
  123. X        return -1;
  124. X          case 0x41:    /* F7 */
  125. X        stuffReadbuff("<<");
  126. X        return -1;
  127. X          case 0x42:    /* F8 */
  128. X        stuffReadbuff(">>");
  129. X        return -1;
  130. X          case 0x43:    /* F9 */
  131. X        stuffReadbuff(":x\n");
  132. X        return -1;
  133. X          case 0x44:    /* F10 */
  134. X        stuffReadbuff(":help\n");
  135. X        return -1;
  136. X          default:
  137. X        break;
  138. X        }
  139. X        break;
  140. X
  141. X      default:
  142. X        return c;
  143. X    }
  144. X    }
  145. X}
  146. X
  147. X#define BSIZE   2048
  148. Xstatic char     outbuf[BSIZE];
  149. Xstatic int      bpos = 0;
  150. X
  151. Xflushbuf()
  152. X{
  153. X    if (bpos != 0)
  154. X    write(1, outbuf, bpos);
  155. X    bpos = 0;
  156. X}
  157. X
  158. X/*
  159. X * Macro to output a character. Used within this file for speed.
  160. X */
  161. X#define outone(c)       outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  162. X
  163. X/*
  164. X * Function version for use outside this file.
  165. X */
  166. X
  167. Xvoid
  168. Xoutchar(c)
  169. X    register char   c;
  170. X{
  171. X    outbuf[bpos++] = c;
  172. X    if (bpos >= BSIZE)
  173. X    flushbuf();
  174. X}
  175. X
  176. Xstatic char     cell[2] = {0, 7};
  177. X
  178. X/*
  179. X * outstr(s) - write a string to the console
  180. X *
  181. X * We implement insert/delete line escape sequences here. This is kind
  182. X * of a kludge, but at least it's localized to a single point.
  183. X */
  184. Xvoid
  185. Xoutstr(s)
  186. X    register char  *s;
  187. X{
  188. X    if (strcmp(s, T_DL) == 0) {    /* delete line */
  189. X    int             r, c;
  190. X
  191. X    flushbuf();
  192. X    VioGetCurPos(&r, &c, 0);
  193. X    VioScrollUp(r, 0, 100, 100, 1, cell, 0);
  194. X    return;
  195. X    }
  196. X    if (strcmp(s, T_IL) == 0) {    /* insert line */
  197. X    int             r, c;
  198. X
  199. X    flushbuf();
  200. X    VioGetCurPos(&r, &c, 0);
  201. X    VioScrollDn(r, 0, 100, 100, 1, cell, 0);
  202. X    return;
  203. X    }
  204. X    while (*s) {
  205. X    outone(*s++);
  206. X    }
  207. X}
  208. X
  209. Xvoid
  210. Xbeep()
  211. X{
  212. X    if (RedrawingDisabled)
  213. X    return;
  214. X
  215. X    outone('\007');
  216. X}
  217. X
  218. Xvoid
  219. Xsleep(n)
  220. X    int             n;
  221. X{
  222. X    DosSleep(1000L * n);
  223. X}
  224. X
  225. Xvoid
  226. Xdelay()
  227. X{
  228. X    flushbuf();
  229. X    DosSleep(300L);
  230. X}
  231. X
  232. Xvoid
  233. Xwindinit()
  234. X{
  235. X    Columns = 80;
  236. X    P(P_LI) = Rows = 25;
  237. X}
  238. X
  239. Xvoid
  240. Xwindexit(r)
  241. X    int             r;
  242. X{
  243. X    flushbuf();
  244. X    exit(r);
  245. X}
  246. X
  247. Xvoid
  248. Xwindgoto(r, c)
  249. X    register int    r, c;
  250. X{
  251. X    flushbuf();
  252. X    VioSetCurPos(r, c, 0);
  253. X}
  254. X
  255. XFILE           *
  256. Xfopenb(fname, mode)
  257. X    char           *fname;
  258. X    char           *mode;
  259. X{
  260. X    FILE           *fopen();
  261. X    char            modestr[16];
  262. X
  263. X    sprintf(modestr, "%sb", mode);
  264. X    return fopen(fname, modestr);
  265. X}
  266. SHAR_EOF
  267. echo "extracting os2.h"
  268. sed 's/^X//' << \SHAR_EOF > os2.h
  269. X/*
  270. X * OS2 Machine-dependent routines. 
  271. X */
  272. X
  273. Xint  inchar();
  274. Xvoid outchar();
  275. Xvoid outstr(), beep();
  276. Xvoid windinit(), windexit(), windgoto();
  277. Xvoid delay();
  278. Xvoid sleep();
  279. SHAR_EOF
  280. echo "extracting param.c"
  281. sed 's/^X//' << \SHAR_EOF > param.c
  282. X/*
  283. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  284. X *
  285. X * Code Contributions By : Tim Thompson           twitch!tjt
  286. X *                         Tony Andrews           onecom!wldrdg!tony 
  287. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  288. X */
  289. X
  290. X/*
  291. X * Code to handle user-settable parameters. This is all pretty much table-
  292. X * driven. To add a new parameter, put it in the params array, and add a
  293. X * macro for it in param.h. If it's a numeric parameter, add any necessary
  294. X * bounds checks to doset(). String parameters aren't currently supported. 
  295. X */
  296. X
  297. X#include "stevie.h"
  298. X
  299. Xstruct param    params[] = {
  300. X
  301. X                {"tabstop", "ts", 8, P_NUM},
  302. X                {"scroll", "scroll", 12, P_NUM},
  303. X                {"report", "report", 5, P_NUM},
  304. X                {"lines", "lines", 25, P_NUM},
  305. X
  306. X                {"vbell", "vb", TRUE, P_BOOL},
  307. X                {"showmatch", "sm", FALSE, P_BOOL},
  308. X                {"wrapscan", "ws", TRUE, P_BOOL},
  309. X                {"errorbells", "eb", FALSE, P_BOOL},
  310. X                {"showmode", "mo", FALSE, P_BOOL},
  311. X                {"backup", "bk", FALSE, P_BOOL},
  312. X                {"return", "cr", TRUE, P_BOOL},
  313. X                {"list", "list", FALSE, P_BOOL},
  314. X                {"ignorecase", "ic", FALSE, P_BOOL},
  315. X                {"autoindent", "ai", FALSE, P_BOOL},
  316. X                {"number", "nu", FALSE, P_BOOL},
  317. X
  318. X                {"", "", 0, 0}    /* end marker */
  319. X};
  320. X
  321. Xstatic void     showparms();
  322. X
  323. Xvoid
  324. Xdoset(arg, inter)
  325. X    char           *arg;    /* parameter string */
  326. X    bool_t          inter;    /* TRUE if called interactively */
  327. X{
  328. X    int             i;
  329. X    char           *s;
  330. X    bool_t          did_lines = FALSE;
  331. X
  332. X    bool_t          state = TRUE;    /* new state of boolean parms. */
  333. X
  334. X    if (arg == NULL) {
  335. X    showparms(FALSE);
  336. X    return;
  337. X    }
  338. X    if (strncmp(arg, "all", 3) == 0) {
  339. X    showparms(TRUE);
  340. X    return;
  341. X    }
  342. X    if (strncmp(arg, "no", 2) == 0) {
  343. X    state = FALSE;
  344. X    arg += 2;
  345. X    }
  346. X    for (i = 0; params[i].fullname[0] != NUL; i++) {
  347. X    s = params[i].fullname;
  348. X    if (strncmp(arg, s, strlen(s)) == 0)    /* matched full name */
  349. X        break;
  350. X    s = params[i].shortname;
  351. X    if (strncmp(arg, s, strlen(s)) == 0)    /* matched short name */
  352. X        break;
  353. X    }
  354. X
  355. X    if (params[i].fullname[0] != NUL) {    /* found a match */
  356. X    if (params[i].flags & P_NUM) {
  357. X        did_lines = (i == P_LI);
  358. X        if (inter && (arg[strlen(s)] != '=' || state == FALSE))
  359. X        emsg("Invalid set of numeric parameter");
  360. X        else {
  361. X        params[i].value = atoi(arg + strlen(s) + 1);
  362. X        params[i].flags |= P_CHANGED;
  363. X        }
  364. X    } else {        /* boolean */
  365. X        if (inter && (arg[strlen(s)] == '='))
  366. X        emsg("Invalid set of boolean parameter");
  367. X        else {
  368. X        params[i].value = state;
  369. X        params[i].flags |= P_CHANGED;
  370. X        }
  371. X    }
  372. X    } else {
  373. X    if (inter)
  374. X        emsg("Unrecognized 'set' option");
  375. X    }
  376. X
  377. X    if (did_lines) {
  378. X    Rows = P(P_LI);
  379. X    screenalloc();        /* allocate new screen buffers */
  380. X    s_clear();
  381. X    }
  382. X    /*
  383. X     * Mark the screen contents as not valid in case we changed something
  384. X     * like "tabstop" or "list" that will change its appearance. 
  385. X     */
  386. X    if (inter)
  387. X    S_NOT_VALID;
  388. X
  389. X    /*
  390. X     * Check the bounds for numeric parameters here 
  391. X     */
  392. X    if (P(P_TS) <= 0 || P(P_TS) > 32) {
  393. X    if (inter)
  394. X        emsg("Invalid tab size specified");
  395. X    P(P_TS) = 8;
  396. X    return;
  397. X    }
  398. X    if (P(P_SS) <= 0 || P(P_SS) > Rows) {
  399. X    if (inter)
  400. X        emsg("Invalid scroll size specified");
  401. X    P(P_SS) = 12;
  402. X    return;
  403. X    }
  404. X    /*
  405. X     * Check for another argument, and call doset() recursively, if found. If
  406. X     * any argument results in an error, no further parameters are processed. 
  407. X     */
  408. X    while (*arg != ' ' && *arg != '\t') {    /* skip to next white space */
  409. X    if (*arg == NUL)
  410. X        return;        /* end of parameter list */
  411. X    arg++;
  412. X    }
  413. X    while (*arg == ' ' || *arg == '\t')    /* skip to next non-white */
  414. X    arg++;
  415. X
  416. X    if (*arg)
  417. X    doset(arg, TRUE);    /* recurse on next parameter, if present */
  418. X}
  419. X
  420. Xstatic void
  421. Xshowparms(all)
  422. X    bool_t          all;    /* show ALL parameters */
  423. X{
  424. X    struct param   *p;
  425. X    char            buf[64];
  426. X
  427. X    gotocmdline(YES, NUL);
  428. X    outstr("Parameters:\r\n");
  429. X
  430. X    for (p = ¶ms[0]; p->fullname[0] != NUL; p++) {
  431. X    if (!all && ((p->flags & P_CHANGED) == 0))
  432. X        continue;
  433. X    if (p->flags & P_BOOL)
  434. X        sprintf(buf, "\t%s%s\r\n",
  435. X            (p->value ? "" : "no"), p->fullname);
  436. X    else
  437. X        sprintf(buf, "\t%s=%d\r\n", p->fullname, p->value);
  438. X
  439. X    outstr(buf);
  440. X    }
  441. X    wait_return();
  442. X}
  443. SHAR_EOF
  444. echo "extracting param.h"
  445. sed 's/^X//' << \SHAR_EOF > param.h
  446. X/*
  447. X * STEVIE - Simply Try this Editor for VI Enthusiasts
  448. X *
  449. X * Code Contributions By : Tim Thompson           twitch!tjt
  450. X *                         Tony Andrews           onecom!wldrdg!tony 
  451. X *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  452. X */
  453. X
  454. X/*
  455. X * Settable parameters 
  456. X */
  457. X
  458. Xstruct param {
  459. X    char           *fullname;    /* full parameter name */
  460. X    char           *shortname;    /* permissible abbreviation */
  461. X    int             value;    /* parameter value */
  462. X    int             flags;
  463. X};
  464. X
  465. Xextern struct param params[];
  466. X
  467. X/*
  468. X * Flags 
  469. X */
  470. X#define    P_BOOL        0x01    /* the parameter is boolean */
  471. X#define    P_NUM        0x02    /* the parameter is numeric */
  472. X#define    P_CHANGED    0x04    /* the parameter has been changed */
  473. X
  474. X/*
  475. X * The following are the indices in the params array for each parameter 
  476. X */
  477. X
  478. X/*
  479. X * Numeric parameters 
  480. X */
  481. X#define    P_TS        0    /* tab size */
  482. X#define    P_SS        1    /* scroll size */
  483. X#define    P_RP        2    /* report */
  484. X#define    P_LI        3    /* lines */
  485. X
  486. X/*
  487. X * Boolean parameters 
  488. X */
  489. X#define    P_VB        4    /* visual bell */
  490. X#define    P_SM        5    /* showmatch */
  491. X#define    P_WS        6    /* wrap scan */
  492. X#define    P_EB        7    /* error bells */
  493. X#define    P_MO        8    /* show mode */
  494. X#define    P_BK        9    /* make backups when writing out files */
  495. X#define    P_CR        10    /* use cr-lf to terminate lines on writes */
  496. X#define    P_LS        11    /* show tabs and newlines graphically */
  497. X#define    P_IC        12    /* ignore case in searches */
  498. X#define    P_AI        13    /* auto-indent */
  499. X#define    P_NU        14    /* number lines on the screen */
  500. X
  501. X/*
  502. X * Macro to get the value of a parameter 
  503. X */
  504. X#define    P(n)    (params[n].value)
  505. SHAR_EOF
  506. echo "extracting porting.doc"
  507. sed 's/^X//' << \SHAR_EOF > porting.doc
  508. X
  509. X         Release Notes for STEVIE - Version 3.31B
  510. X
  511. X                   Porting
  512. X
  513. X             Tony Andrews -  March 6, 1988
  514. X            G. R. Walter -  January 6, 1988
  515. X
  516. X
  517. X    Porting the editor is a relatively simple task. Most of the
  518. Xcode is pretty machine-independent. For each environment, there is
  519. Xa file of routines that perform various low-level operations that
  520. Xtend to vary a lot from one machine to another. Another file contains
  521. Xthe escape sequences to be used for each machine.
  522. X
  523. XNote however that 'char' is treated as unsigned so you need to set the
  524. Xappropriate compiler flags if this is not the default.
  525. X
  526. X    The machine-dependent files currently used are:
  527. X
  528. Xtos.c:     Atari ST - ifdef for either Megamax or Alcyon
  529. Xtos.h
  530. X
  531. Xunix.c:     UNIX System V
  532. Xunix.h
  533. X
  534. Xos2.c:     Microsoft OS/2
  535. Xos2.h
  536. X
  537. Xdos.c:   MS DOS
  538. Xdos.h
  539. X
  540. Xamiga.c: Amiga
  541. Xamiga.h
  542. X
  543. Xbsd.c:   BSD 4.3 UNIX
  544. Xbsd.h
  545. X
  546. X    Each of these files are around 150 lines long and deal with
  547. Xlow-level issues like character I/O to the terminal, terminal
  548. Xinitialization, cursor addressing, and so on. There are different
  549. Xtradeoffs to be made depending on the environment. For example, the
  550. XUNIX version buffers terminal output because of the relatively high
  551. Xoverhead of system calls. A quick look at the files will make it clear
  552. Xwhat needs to be done in a new environment.
  553. X
  554. X    Terminal escape sequences are in the file "term.h". These are
  555. Xdefined statically, for the time being. There is some discussion in
  556. Xterm.h regarding which sequences are optional and which are not. The
  557. Xeditor is somewhat flexible in dealing with a lack of terminal
  558. Xcapabilities.
  559. X
  560. X    The character set is in the file "charset.c".
  561. X
  562. X    Because not all C compilers support command line macro definitions,
  563. Xthe #define's for system-specific macros are placed in the file "env.h".
  564. XIf you port to a new system, add another line there to define the macro you
  565. Xchoose for your port.
  566. X
  567. X    The basic process for doing a new port is:
  568. X
  569. X    1. Come up with a macro name to use when ifdef'ing your system-
  570. X       specific changes. Add a line to 'env.h' to define
  571. X       the macro name you've chosen.
  572. X
  573. X    2. Look at amiga.c, bsd.c, unix.c, tos.c, dos.c and os2.c and copy the
  574. X       one that comes closest to working on your system. Then modify your
  575. X       new file as needed.
  576. X
  577. X    3. Look at term.h and edit the file appropriately adding a new
  578. X       set of escape sequence definitions for your system.
  579. X
  580. X    4. Compiling and debug the editor.
  581. SHAR_EOF
  582. echo "extracting regexp.c"
  583. sed 's/^X//' << \SHAR_EOF > regexp.c
  584. X/*
  585. X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  586. X *
  587. X * This is NOT the original regular expression code as written by
  588. X * Henry Spencer. This code has been modified specifically for use
  589. X * with the STEVIE editor, and should not be used apart from compiling
  590. X * STEVIE. If you want a good regular expression library, get the
  591. X * original code. The copyright notice that follows is from the
  592. X * original.
  593. X *
  594. X * NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE
  595. X *
  596. X *
  597. X * regcomp and regexec -- regsub and regerror are elsewhere
  598. X *
  599. X *      Copyright (c) 1986 by University of Toronto.
  600. X *      Written by Henry Spencer.  Not derived from licensed software.
  601. X *
  602. X *      Permission is granted to anyone to use this software for any
  603. X *      purpose on any computer system, and to redistribute it freely,
  604. X *      subject to the following restrictions:
  605. X *
  606. X *      1. The author is not responsible for the consequences of use of
  607. X *              this software, no matter how awful, even if they arise
  608. X *              from defects in it.
  609. X *
  610. X *      2. The origin of this software must not be misrepresented, either
  611. X *              by explicit claim or by omission.
  612. X *
  613. X *      3. Altered versions must be plainly marked as such, and must not
  614. X *              be misrepresented as being the original software.
  615. X *
  616. X * Beware that some of this code is subtly aware of the way operator
  617. X * precedence is structured in regular expressions.  Serious changes in
  618. X * regular-expression syntax might require a total rethink.
  619. X *
  620. X * $Log:        regexp.c,v $
  621. X * Revision 1.2  88/04/28  08:09:45  tony
  622. X * First modification of the regexp library. Added an external variable
  623. X * 'reg_ic' which can be set to indicate that case should be ignored.
  624. X * Added a new parameter to regexec() to indicate that the given string
  625. X * comes from the beginning of a line and is thus eligible to match
  626. X * 'beginning-of-line'.
  627. X * 
  628. X */
  629. X#include "env.h"
  630. X
  631. X#ifdef  MEGAMAX
  632. Xoverlay "regexp"
  633. X#endif
  634. X
  635. X#include <stdio.h>
  636. X#include "regexp.h"
  637. X#include "regmagic.h"
  638. X
  639. X/*
  640. X * The "internal use only" fields in regexp.h are present to pass info from
  641. X * compile to execute that permits the execute phase to run lots faster on
  642. X * simple cases.  They are:
  643. X *
  644. X * regstart     char that must begin a match; '\0' if none obvious
  645. X * reganch      is the match anchored (at beginning-of-line only)?
  646. X * regmust      string (pointer into program) that match must include, or NULL
  647. X * regmlen      length of regmust string
  648. X *
  649. X * Regstart and reganch permit very fast decisions on suitable starting points
  650. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  651. X * of lines that cannot possibly match.  The regmust tests are costly enough
  652. X * that regcomp() supplies a regmust only if the r.e. contains something
  653. X * potentially expensive (at present, the only such thing detected is * or +
  654. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  655. X * supplied because the test in regexec() needs it and regcomp() is computing
  656. X * it anyway.
  657. X */
  658. X
  659. X/*
  660. X * Structure for regexp "program".  This is essentially a linear encoding
  661. X * of a nondeterministic finite-state machine (aka syntax charts or
  662. X * "railroad normal form" in parsing technology).  Each node is an opcode
  663. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  664. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  665. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  666. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  667. X * opposed to a collection of them) is never concatenated with anything
  668. X * because of operator precedence.)  The operand of some types of node is
  669. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  670. X * particular, the operand of a BRANCH node is the first node of the branch.
  671. X * (NB this is *not* a tree structure:  the tail of the branch connects
  672. X * to the thing following the set of BRANCHes.)  The opcodes are:
  673. X */
  674. X
  675. X/* definition   number  opnd?   meaning */
  676. X#define END     0        /* no   End of program. */
  677. X#define BOL     1        /* no   Match "" at beginning of line. */
  678. X#define EOL     2        /* no   Match "" at end of line. */
  679. X#define ANY     3        /* no   Match any one character. */
  680. X#define ANYOF   4        /* str  Match any character in this string. */
  681. X#define ANYBUT  5        /* str  Match any character not in this
  682. X                 * string. */
  683. X#define BRANCH  6        /* node Match this alternative, or the
  684. X                 * next... */
  685. X#define BACK    7        /* no   Match "", "next" ptr points backward. */
  686. X#define EXACTLY 8        /* str  Match this string. */
  687. X#define NOTHING 9        /* no   Match empty string. */
  688. X#define STAR    10        /* node Match this (simple) thing 0 or more
  689. X                 * times. */
  690. X#define PLUS    11        /* node Match this (simple) thing 1 or more
  691. X                 * times. */
  692. X#define OPEN    20        /* no   Mark this point in input as start of
  693. X                 * #n. */
  694. X /* OPEN+1 is number 1, etc. */
  695. X#define CLOSE   30        /* no   Analogous to OPEN. */
  696. X
  697. X/*
  698. X * Opcode notes:
  699. X *
  700. X * BRANCH       The set of branches constituting a single choice are hooked
  701. X *              together with their "next" pointers, since precedence prevents
  702. X *              anything being concatenated to any individual branch.  The
  703. X *              "next" pointer of the last BRANCH in a choice points to the
  704. X *              thing following the whole choice.  This is also where the
  705. X *              final "next" pointer of each individual branch points; each
  706. X *              branch starts with the operand node of a BRANCH node.
  707. X *
  708. X * BACK         Normal "next" pointers all implicitly point forward; BACK
  709. X *              exists to make loop structures possible.
  710. X *
  711. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  712. X *              BRANCH structures using BACK.  Simple cases (one character
  713. X *              per match) are implemented with STAR and PLUS for speed
  714. X *              and to minimize recursive plunges.
  715. X *
  716. X * OPEN,CLOSE   ...are numbered at compile time.
  717. X */
  718. X
  719. X/*
  720. X * A node is one char of opcode followed by two chars of "next" pointer.
  721. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  722. X * value is a positive offset from the opcode of the node containing it.
  723. X * An operand, if any, simply follows the node.  (Note that much of the
  724. X * code generation knows about this implicit relationship.)
  725. X *
  726. X * Using two bytes for the "next" pointer is vast overkill for most things,
  727. X * but allows patterns to get big without disasters.
  728. X */
  729. X#define OP(p)   (*(p))
  730. X#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
  731. X#define OPERAND(p)      ((p) + 3)
  732. X
  733. X/*
  734. X * See regmagic.h for one further detail of program structure.
  735. X */
  736. X
  737. X
  738. X/*
  739. X * Utility definitions.
  740. X */
  741. X#ifndef CHARBITS
  742. X#define UCHARAT(p)      ((int)*(unsigned char *)(p))
  743. X#else
  744. X#define UCHARAT(p)      ((int)*(p)&CHARBITS)
  745. X#endif
  746. X
  747. X#define FAIL(m) { regerror(m); return(NULL); }
  748. X#define ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
  749. X#define META    "^$.[()|?+*\\"
  750. X
  751. X/*
  752. X * Flags to be passed up and down.
  753. X */
  754. X#define HASWIDTH        01    /* Known never to match null string. */
  755. X#define SIMPLE          02    /* Simple enough to be STAR/PLUS operand. */
  756. X#define SPSTART         04    /* Starts with * or +. */
  757. X#define WORST           0    /* Worst case. */
  758. X
  759. X#ifndef ORIGINAL
  760. X/*
  761. X * The following supports the ability to ignore case in searches.
  762. X */
  763. X
  764. X#include <ctype.h>
  765. X
  766. Xint             reg_ic = 0;    /* set by callers to ignore case */
  767. X
  768. X/*
  769. X * mkup - convert to upper case IF we're doing caseless compares
  770. X */
  771. X#define mkup(c)         ((islower(c) && reg_ic) ? toupper(c) : (c))
  772. X
  773. X#endif
  774. X
  775. X/*
  776. X * Global work variables for regcomp().
  777. X */
  778. Xstatic char    *regparse;    /* Input-scan pointer. */
  779. Xstatic int      regnpar;    /* () count. */
  780. Xstatic char     regdummy;
  781. Xstatic char    *regcode;    /* Code-emit pointer; ®dummy = don't. */
  782. Xstatic long     regsize;    /* Code size. */
  783. X
  784. X/*
  785. X * Forward declarations for regcomp()'s friends.
  786. X */
  787. X#ifndef STATIC
  788. X#define STATIC  static
  789. X#endif
  790. XSTATIC char    *reg();
  791. XSTATIC char    *regbranch();
  792. XSTATIC char    *regpiece();
  793. XSTATIC char    *regatom();
  794. XSTATIC char    *regnode();
  795. XSTATIC char    *regnext();
  796. XSTATIC void     regc();
  797. XSTATIC void     reginsert();
  798. XSTATIC void     regtail();
  799. XSTATIC void     regoptail();
  800. X#ifdef STRCSPN
  801. XSTATIC int      strcspn();
  802. X#endif
  803. X
  804. X/*
  805. X - regcomp - compile a regular expression into internal code
  806. X *
  807. X * We can't allocate space until we know how big the compiled form will be,
  808. X * but we can't compile it (and thus know how big it is) until we've got a
  809. X * place to put the code.  So we cheat:  we compile it twice, once with code
  810. X * generation turned off and size counting turned on, and once "for real".
  811. X * This also means that we don't allocate space until we are sure that the
  812. X * thing really will compile successfully, and we never have to move the
  813. X * code and thus invalidate pointers into it.  (Note that it has to be in
  814. X * one piece because free() must be able to free it all.)
  815. X *
  816. X * Beware that the optimization-preparation code in here knows about some
  817. X * of the structure of the compiled regexp.
  818. X */
  819. Xregexp         *
  820. Xregcomp(exp)
  821. X    char           *exp;
  822. X{
  823. X    register regexp *r;
  824. X    register char  *scan;
  825. X    register char  *longest;
  826. X    register int    len;
  827. X    int             flags;
  828. X/*  extern char    *malloc();*/
  829. X    extern char    *alloc();
  830. X
  831. X    if (exp == NULL)
  832. X    FAIL("NULL argument");
  833. X
  834. X    /* First pass: determine size, legality. */
  835. X    regparse = exp;
  836. X    regnpar = 1;
  837. X    regsize = 0L;
  838. X    regcode = ®dummy;
  839. X    regc(MAGIC);
  840. X    if (reg(0, &flags) == NULL)
  841. X    return (NULL);
  842. X
  843. X    /* Small enough for pointer-storage convention? */
  844. X    if (regsize >= 32767L)    /* Probably could be 65535L. */
  845. X    FAIL("regexp too big");
  846. X
  847. X    /* Allocate space. */
  848. X/*  r = (regexp *) malloc((unsigned) (sizeof(regexp) + regsize));*/
  849. X    r = (regexp *) alloc((unsigned) (sizeof(regexp) + regsize));
  850. X    if (r == NULL)
  851. X    FAIL("out of space");
  852. X
  853. X    /* Second pass: emit code. */
  854. X    regparse = exp;
  855. X    regnpar = 1;
  856. X    regcode = r->program;
  857. X    regc(MAGIC);
  858. X    if (reg(0, &flags) == NULL)
  859. X    return (NULL);
  860. X
  861. X    /* Dig out information for optimizations. */
  862. X    r->regstart = '\0';        /* Worst-case defaults. */
  863. X    r->reganch = 0;
  864. X    r->regmust = NULL;
  865. X    r->regmlen = 0;
  866. X    scan = r->program + 1;    /* First BRANCH. */
  867. X    if (OP(regnext(scan)) == END) {    /* Only one top-level choice. */
  868. X    scan = OPERAND(scan);
  869. X
  870. X    /* Starting-point info. */
  871. X    if (OP(scan) == EXACTLY)
  872. X        r->regstart = *OPERAND(scan);
  873. X    else if (OP(scan) == BOL)
  874. X        r->reganch++;
  875. X
  876. X    /*
  877. X     * If there's something expensive in the r.e., find the longest
  878. X     * literal string that must appear and make it the regmust.  Resolve
  879. X     * ties in favor of later strings, since the regstart check works
  880. X     * with the beginning of the r.e. and avoiding duplication
  881. X     * strengthens checking.  Not a strong reason, but sufficient in the
  882. X     * absence of others. 
  883. X     */
  884. X    if (flags & SPSTART) {
  885. X        longest = NULL;
  886. X        len = 0;
  887. X        for (; scan != NULL; scan = regnext(scan))
  888. X        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  889. X            longest = OPERAND(scan);
  890. X            len = strlen(OPERAND(scan));
  891. X        }
  892. X        r->regmust = longest;
  893. X        r->regmlen = len;
  894. X    }
  895. X    }
  896. X    return (r);
  897. X}
  898. X
  899. X/*
  900. X - reg - regular expression, i.e. main body or parenthesized thing
  901. X *
  902. X * Caller must absorb opening parenthesis.
  903. X *
  904. X * Combining parenthesis handling with the base level of regular expression
  905. X * is a trifle forced, but the need to tie the tails of the branches to what
  906. X * follows makes it hard to avoid.
  907. X */
  908. Xstatic char    *
  909. Xreg(paren, flagp)
  910. X    int             paren;    /* Parenthesized? */
  911. X    int            *flagp;
  912. X{
  913. X    register char  *ret;
  914. X    register char  *br;
  915. X    register char  *ender;
  916. X    register int    parno;
  917. X    int             flags;
  918. X
  919. X    *flagp = HASWIDTH;        /* Tentatively. */
  920. X
  921. X    /* Make an OPEN node, if parenthesized. */
  922. X    if (paren) {
  923. X    if (regnpar >= NSUBEXP)
  924. X        FAIL("too many ()");
  925. X    parno = regnpar;
  926. X    regnpar++;
  927. X    ret = regnode(OPEN + parno);
  928. X    } else
  929. X    ret = NULL;
  930. X
  931. X    /* Pick up the branches, linking them together. */
  932. X    br = regbranch(&flags);
  933. X    if (br == NULL)
  934. X    return (NULL);
  935. X    if (ret != NULL)
  936. X    regtail(ret, br);    /* OPEN -> first. */
  937. X    else
  938. X    ret = br;
  939. X    if (!(flags & HASWIDTH))
  940. X    *flagp &= ~HASWIDTH;
  941. X    *flagp |= flags & SPSTART;
  942. X    while (*regparse == '|') {
  943. X    regparse++;
  944. X    br = regbranch(&flags);
  945. X    if (br == NULL)
  946. X        return (NULL);
  947. X    regtail(ret, br);    /* BRANCH -> BRANCH. */
  948. X    if (!(flags & HASWIDTH))
  949. X        *flagp &= ~HASWIDTH;
  950. X    *flagp |= flags & SPSTART;
  951. X    }
  952. X
  953. X    /* Make a closing node, and hook it on the end. */
  954. X    ender = regnode((paren) ? CLOSE + parno : END);
  955. X    regtail(ret, ender);
  956. X
  957. X    /* Hook the tails of the branches to the closing node. */
  958. X    for (br = ret; br != NULL; br = regnext(br))
  959. X    regoptail(br, ender);
  960. X
  961. X    /* Check for proper termination. */
  962. X    if (paren && *regparse++ != ')') {
  963. X    FAIL("unmatched ()");
  964. X    } else if (!paren && *regparse != '\0') {
  965. X    if (*regparse == ')') {
  966. X        FAIL("unmatched ()");
  967. X    } else
  968. X        FAIL("junk on end");/* "Can't happen". */
  969. X    /* NOTREACHED */
  970. X    }
  971. X    return (ret);
  972. X}
  973. X
  974. X/*
  975. X - regbranch - one alternative of an | operator
  976. X *
  977. X * Implements the concatenation operator.
  978. X */
  979. Xstatic char    *
  980. Xregbranch(flagp)
  981. X    int            *flagp;
  982. X{
  983. X    register char  *ret;
  984. X    register char  *chain;
  985. X    register char  *latest;
  986. X    int             flags;
  987. X
  988. X    *flagp = WORST;        /* Tentatively. */
  989. X
  990. X    ret = regnode(BRANCH);
  991. X    chain = NULL;
  992. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  993. X    latest = regpiece(&flags);
  994. X    if (latest == NULL)
  995. X        return (NULL);
  996. X    *flagp |= flags & HASWIDTH;
  997. X    if (chain == NULL)    /* First piece. */
  998. X        *flagp |= flags & SPSTART;
  999. X    else
  1000. X        regtail(chain, latest);
  1001. X    chain = latest;
  1002. X    }
  1003. X    if (chain == NULL)        /* Loop ran zero times. */
  1004. X    (void) regnode(NOTHING);
  1005. X
  1006. X    return (ret);
  1007. X}
  1008. X
  1009. X/*
  1010. X - regpiece - something followed by possible [*+?]
  1011. X *
  1012. X * Note that the branching code sequences used for ? and the general cases
  1013. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  1014. X * both the endmarker for their branch list and the body of the last branch.
  1015. X * It might seem that this node could be dispensed with entirely, but the
  1016. X * endmarker role is not redundant.
  1017. X */
  1018. Xstatic char    *
  1019. Xregpiece(flagp)
  1020. X    int            *flagp;
  1021. X{
  1022. X    register char  *ret;
  1023. X    register char   op;
  1024. X    register char  *next;
  1025. X    int             flags;
  1026. X
  1027. X    ret = regatom(&flags);
  1028. X    if (ret == NULL)
  1029. X    return (NULL);
  1030. X
  1031. X    op = *regparse;
  1032. X    if (!ISMULT(op)) {
  1033. X    *flagp = flags;
  1034. X    return (ret);
  1035. X    }
  1036. X    if (!(flags & HASWIDTH) && op != '?')
  1037. X    FAIL("*+ operand could be empty");
  1038. X    *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
  1039. X
  1040. X    if (op == '*' && (flags & SIMPLE))
  1041. X    reginsert(STAR, ret);
  1042. X    else if (op == '*') {
  1043. X    /* Emit x* as (x&|), where & means "self". */
  1044. X    reginsert(BRANCH, ret);    /* Either x */
  1045. X    regoptail(ret, regnode(BACK));    /* and loop */
  1046. X    regoptail(ret, ret);    /* back */
  1047. X    regtail(ret, regnode(BRANCH));    /* or */
  1048. X    regtail(ret, regnode(NOTHING));    /* null. */
  1049. X    } else if (op == '+' && (flags & SIMPLE))
  1050. X    reginsert(PLUS, ret);
  1051. X    else if (op == '+') {
  1052. X    /* Emit x+ as x(&|), where & means "self". */
  1053. X    next = regnode(BRANCH);    /* Either */
  1054. X    regtail(ret, next);
  1055. X    regtail(regnode(BACK), ret);    /* loop back */
  1056. X    regtail(next, regnode(BRANCH));    /* or */
  1057. X    regtail(ret, regnode(NOTHING));    /* null. */
  1058. X    } else if (op == '?') {
  1059. X    /* Emit x? as (x|) */
  1060. X    reginsert(BRANCH, ret);    /* Either x */
  1061. X    regtail(ret, regnode(BRANCH));    /* or */
  1062. X    next = regnode(NOTHING);/* null. */
  1063. X    regtail(ret, next);
  1064. X    regoptail(ret, next);
  1065. X    }
  1066. X    regparse++;
  1067. X    if (ISMULT(*regparse))
  1068. X    FAIL("nested *?+");
  1069. X
  1070. X    return (ret);
  1071. X}
  1072. X
  1073. X/*
  1074. X - regatom - the lowest level
  1075. X *
  1076. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  1077. X * it can turn them into a single node, which is smaller to store and
  1078. X * faster to run.  Backslashed characters are exceptions, each becoming a
  1079. X * separate node; the code is simpler that way and it's not worth fixing.
  1080. X */
  1081. Xstatic char    *
  1082. Xregatom(flagp)
  1083. X    int            *flagp;
  1084. X{
  1085. X    register char  *ret;
  1086. X    int             flags;
  1087. X
  1088. X    *flagp = WORST;        /* Tentatively. */
  1089. X
  1090. X    switch (*regparse++) {
  1091. X      case '^':
  1092. X    ret = regnode(BOL);
  1093. X    break;
  1094. X      case '$':
  1095. X    ret = regnode(EOL);
  1096. X    break;
  1097. X      case '.':
  1098. X    ret = regnode(ANY);
  1099. X    *flagp |= HASWIDTH | SIMPLE;
  1100. X    break;
  1101. X      case '[':{
  1102. X        register int    class;
  1103. X        register int    classend;
  1104. X
  1105. X        if (*regparse == '^') {    /* Complement of range. */
  1106. X        ret = regnode(ANYBUT);
  1107. X        regparse++;
  1108. X        } else
  1109. X        ret = regnode(ANYOF);
  1110. X        if (*regparse == ']' || *regparse == '-')
  1111. X        regc(*regparse++);
  1112. X        while (*regparse != '\0' && *regparse != ']') {
  1113. X        if (*regparse == '-') {
  1114. X            regparse++;
  1115. X            if (*regparse == ']' || *regparse == '\0')
  1116. X            regc('-');
  1117. X            else {
  1118. X            class = UCHARAT(regparse - 2) + 1;
  1119. X            classend = UCHARAT(regparse);
  1120. X            if (class > classend + 1)
  1121. X                FAIL("invalid [] range");
  1122. X            for (; class <= classend; class++)
  1123. X                regc(class);
  1124. X            regparse++;
  1125. X            }
  1126. X        } else
  1127. X            regc(*regparse++);
  1128. X        }
  1129. X        regc('\0');
  1130. X        if (*regparse != ']')
  1131. X        FAIL("unmatched []");
  1132. X        regparse++;
  1133. X        *flagp |= HASWIDTH | SIMPLE;
  1134. X    }
  1135. X    break;
  1136. X      case '(':
  1137. X    ret = reg(1, &flags);
  1138. X    if (ret == NULL)
  1139. X        return (NULL);
  1140. X    *flagp |= flags & (HASWIDTH | SPSTART);
  1141. X    break;
  1142. X      case '\0':
  1143. X      case '|':
  1144. X      case ')':
  1145. X    FAIL("internal urp");    /* Supposed to be caught earlier. */
  1146. X    /* break; Not Reached */
  1147. X      case '?':
  1148. X      case '+':
  1149. X      case '*':
  1150. X    FAIL("?+* follows nothing");
  1151. X    /* break; Not Reached */
  1152. X      case '\\':
  1153. X    if (*regparse == '\0')
  1154. X        FAIL("trailing \\");
  1155. X    ret = regnode(EXACTLY);
  1156. X    regc(*regparse++);
  1157. X    regc('\0');
  1158. X    *flagp |= HASWIDTH | SIMPLE;
  1159. X    break;
  1160. X      default:{
  1161. X        register int    len;
  1162. X        register char   ender;
  1163. X
  1164. X        regparse--;
  1165. X        len = strcspn(regparse, META);
  1166. X        if (len <= 0)
  1167. X        FAIL("internal disaster");
  1168. X        ender = *(regparse + len);
  1169. X        if (len > 1 && ISMULT(ender))
  1170. X        len--;        /* Back off clear of ?+* operand. */
  1171. X        *flagp |= HASWIDTH;
  1172. X        if (len == 1)
  1173. X        *flagp |= SIMPLE;
  1174. X        ret = regnode(EXACTLY);
  1175. X        while (len > 0) {
  1176. X        regc(*regparse++);
  1177. X        len--;
  1178. X        }
  1179. X        regc('\0');
  1180. X    }
  1181. X    break;
  1182. X    }
  1183. X
  1184. X    return (ret);
  1185. X}
  1186. X
  1187. X/*
  1188. X - regnode - emit a node
  1189. X */
  1190. Xstatic char    *        /* Location. */
  1191. Xregnode(op)
  1192. X    char            op;
  1193. X{
  1194. X    register char  *ret;
  1195. X    register char  *ptr;
  1196. X
  1197. X    ret = regcode;
  1198. X    if (ret == ®dummy) {
  1199. X    regsize += 3;
  1200. X    return (ret);
  1201. X    }
  1202. X    ptr = ret;
  1203. X    *ptr++ = op;
  1204. X    *ptr++ = '\0';        /* Null "next" pointer. */
  1205. X    *ptr++ = '\0';
  1206. X    regcode = ptr;
  1207. X
  1208. X    return (ret);
  1209. X}
  1210. X
  1211. X/*
  1212. X - regc - emit (if appropriate) a byte of code
  1213. X */
  1214. Xstatic void
  1215. Xregc(b)
  1216. X    char            b;
  1217. X{
  1218. X    if (regcode != ®dummy)
  1219. X    *regcode++ = b;
  1220. X    else
  1221. X    regsize++;
  1222. X}
  1223. X
  1224. X/*
  1225. X - reginsert - insert an operator in front of already-emitted operand
  1226. X *
  1227. X * Means relocating the operand.
  1228. X */
  1229. Xstatic void
  1230. Xreginsert(op, opnd)
  1231. X    char            op;
  1232. X    char           *opnd;
  1233. X{
  1234. X    register char  *src;
  1235. X    register char  *dst;
  1236. X    register char  *place;
  1237. X
  1238. X    if (regcode == ®dummy) {
  1239. X    regsize += 3;
  1240. X    return;
  1241. X    }
  1242. X    src = regcode;
  1243. X    regcode += 3;
  1244. X    dst = regcode;
  1245. X    while (src > opnd)
  1246. X    *--dst = *--src;
  1247. X
  1248. X    place = opnd;        /* Op node, where operand used to be. */
  1249. X    *place++ = op;
  1250. X    *place++ = '\0';
  1251. X    *place = '\0';
  1252. X}
  1253. X
  1254. X/*
  1255. X - regtail - set the next-pointer at the end of a node chain
  1256. X */
  1257. Xstatic void
  1258. Xregtail(p, val)
  1259. X    char           *p;
  1260. X    char           *val;
  1261. X{
  1262. X    register char  *scan;
  1263. X    register char  *temp;
  1264. X    register int    offset;
  1265. X
  1266. X    if (p == ®dummy)
  1267. X    return;
  1268. X
  1269. X    /* Find last node. */
  1270. X    scan = p;
  1271. X    for (;;) {
  1272. X    temp = regnext(scan);
  1273. X    if (temp == NULL)
  1274. X        break;
  1275. X    scan = temp;
  1276. X    }
  1277. X
  1278. X    if (OP(scan) == BACK)
  1279. X    offset = scan - val;
  1280. X    else
  1281. X    offset = val - scan;
  1282. X    *(scan + 1) = (char) ((offset >> 8) & 0377);
  1283. X    *(scan + 2) = (char) (offset & 0377);
  1284. X}
  1285. X
  1286. X/*
  1287. X - regoptail - regtail on operand of first argument; nop if operandless
  1288. X */
  1289. Xstatic void
  1290. Xregoptail(p, val)
  1291. X    char           *p;
  1292. X    char           *val;
  1293. X{
  1294. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  1295. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  1296. X    return;
  1297. X    regtail(OPERAND(p), val);
  1298. X}
  1299. X
  1300. X/*
  1301. X * regexec and friends
  1302. X */
  1303. X
  1304. X/*
  1305. X * Global work variables for regexec().
  1306. X */
  1307. Xstatic char    *reginput;    /* String-input pointer. */
  1308. Xstatic char    *regbol;        /* Beginning of input, for ^ check. */
  1309. Xstatic char   **regstartp;    /* Pointer to startp array. */
  1310. Xstatic char   **regendp;    /* Ditto for endp. */
  1311. X
  1312. X/*
  1313. X * Forwards.
  1314. X */
  1315. XSTATIC int      regtry();
  1316. XSTATIC int      regmatch();
  1317. XSTATIC int      regrepeat();
  1318. X
  1319. X#ifdef DEBUG
  1320. Xint             regnarrate = 0;
  1321. Xvoid            regdump();
  1322. XSTATIC char    *regprop();
  1323. X#endif
  1324. X
  1325. X/*
  1326. X - regexec - match a regexp against a string
  1327. X */
  1328. Xint
  1329. Xregexec(prog, string, at_bol)
  1330. X    register regexp *prog;
  1331. X    register char  *string;
  1332. X    int             at_bol;
  1333. X{
  1334. X    register char  *s;
  1335. X    extern char    *cstrchr();
  1336. X
  1337. X    /* Be paranoid... */
  1338. X    if (prog == NULL || string == NULL) {
  1339. X    regerror("NULL parameter");
  1340. X    return (0);
  1341. X    }
  1342. X    /* Check validity of program. */
  1343. X    if (UCHARAT(prog->program) != MAGIC) {
  1344. X    regerror("corrupted program");
  1345. X    return (0);
  1346. X    }
  1347. X    /* If there is a "must appear" string, look for it. */
  1348. X    if (prog->regmust != NULL) {
  1349. X    s = string;
  1350. X    while ((s = cstrchr(s, prog->regmust[0])) != NULL) {
  1351. X        if (cstrncmp(s, prog->regmust, prog->regmlen) == 0)
  1352. X        break;        /* Found it. */
  1353. X        s++;
  1354. X    }
  1355. X    if (s == NULL)        /* Not present. */
  1356. X        return (0);
  1357. X    }
  1358. X    /* Mark beginning of line for ^ . */
  1359. X    if (at_bol)
  1360. X    regbol = string;    /* is possible to match bol */
  1361. X    else
  1362. X    regbol = NULL;        /* we aren't there, so don't match it */
  1363. X
  1364. X    /* Simplest case:  anchored match need be tried only once. */
  1365. X    if (prog->reganch)
  1366. X    return (regtry(prog, string));
  1367. X
  1368. X    /* Messy cases:  unanchored match. */
  1369. X    s = string;
  1370. X    if (prog->regstart != '\0')
  1371. X    /* We know what char it must start with. */
  1372. X    while ((s = cstrchr(s, prog->regstart)) != NULL) {
  1373. X        if (regtry(prog, s))
  1374. X        return (1);
  1375. X        s++;
  1376. X    }
  1377. X    else
  1378. X    /* We don't -- general case. */
  1379. X    do {
  1380. X        if (regtry(prog, s))
  1381. X        return (1);
  1382. X    } while (*s++ != '\0');
  1383. X
  1384. X    /* Failure. */
  1385. X    return (0);
  1386. X}
  1387. X
  1388. X/*
  1389. X - regtry - try match at specific point
  1390. X */
  1391. Xstatic int            /* 0 failure, 1 success */
  1392. Xregtry(prog, string)
  1393. X    regexp         *prog;
  1394. X    char           *string;
  1395. X{
  1396. X    register int    i;
  1397. X    register char **sp;
  1398. X    register char **ep;
  1399. X
  1400. X    reginput = string;
  1401. X    regstartp = prog->startp;
  1402. X    regendp = prog->endp;
  1403. X
  1404. X    sp = prog->startp;
  1405. X    ep = prog->endp;
  1406. X    for (i = NSUBEXP; i > 0; i--) {
  1407. X    *sp++ = NULL;
  1408. X    *ep++ = NULL;
  1409. X    }
  1410. X    if (regmatch(prog->program + 1)) {
  1411. X    prog->startp[0] = string;
  1412. X    prog->endp[0] = reginput;
  1413. X    return (1);
  1414. X    } else
  1415. X    return (0);
  1416. X}
  1417. X
  1418. X/*
  1419. X - regmatch - main matching routine
  1420. X *
  1421. X * Conceptually the strategy is simple:  check to see whether the current
  1422. X * node matches, call self recursively to see whether the rest matches,
  1423. X * and then act accordingly.  In practice we make some effort to avoid
  1424. X * recursion, in particular by going through "ordinary" nodes (that don't
  1425. X * need to know whether the rest of the match failed) by a loop instead of
  1426. X * by recursion.
  1427. X */
  1428. Xstatic int            /* 0 failure, 1 success */
  1429. Xregmatch(prog)
  1430. X    char           *prog;
  1431. X{
  1432. X    register char  *scan;    /* Current node. */
  1433. X    char           *next;    /* Next node. */
  1434. X    extern char    *strchr();
  1435. X
  1436. X    scan = prog;
  1437. X#ifdef DEBUG
  1438. X    if (scan != NULL && regnarrate)
  1439. X    fprintf(stderr, "%s(\n", regprop(scan));
  1440. X#endif
  1441. X    while (scan != NULL) {
  1442. X#ifdef DEBUG
  1443. X    if (regnarrate)
  1444. X        fprintf(stderr, "%s...\n", regprop(scan));
  1445. X#endif
  1446. X    next = regnext(scan);
  1447. X
  1448. X    switch (OP(scan)) {
  1449. X      case BOL:
  1450. X        if (reginput != regbol)
  1451. X        return (0);
  1452. X        break;
  1453. X      case EOL:
  1454. X        if (*reginput != '\0')
  1455. X        return (0);
  1456. X        break;
  1457. X      case ANY:
  1458. X        if (*reginput == '\0')
  1459. X        return (0);
  1460. X        reginput++;
  1461. X        break;
  1462. X      case EXACTLY:{
  1463. X        register int    len;
  1464. X        register char  *opnd;
  1465. X
  1466. X        opnd = OPERAND(scan);
  1467. X        /* Inline the first character, for speed. */
  1468. X        if (mkup(*opnd) != mkup(*reginput))
  1469. X            return (0);
  1470. X        len = strlen(opnd);
  1471. X        if (len > 1 && cstrncmp(opnd, reginput, len) != 0)
  1472. X            return (0);
  1473. X        reginput += len;
  1474. X        }
  1475. X        break;
  1476. X      case ANYOF:
  1477. X        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1478. X        return (0);
  1479. X        reginput++;
  1480. X        break;
  1481. X      case ANYBUT:
  1482. X        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1483. X        return (0);
  1484. X        reginput++;
  1485. X        break;
  1486. X      case NOTHING:
  1487. X        break;
  1488. X      case BACK:
  1489. X        break;
  1490. X      case OPEN + 1:
  1491. X      case OPEN + 2:
  1492. X      case OPEN + 3:
  1493. X      case OPEN + 4:
  1494. X      case OPEN + 5:
  1495. X      case OPEN + 6:
  1496. X      case OPEN + 7:
  1497. X      case OPEN + 8:
  1498. X      case OPEN + 9:{
  1499. X        register int    no;
  1500. X        register char  *save;
  1501. X
  1502. X        no = OP(scan) - OPEN;
  1503. X        save = reginput;
  1504. X
  1505. X        if (regmatch(next)) {
  1506. X            /*
  1507. X             * Don't set startp if some later invocation of the same
  1508. X             * parentheses already has. 
  1509. X             */
  1510. X            if (regstartp[no] == NULL)
  1511. X            regstartp[no] = save;
  1512. X            return (1);
  1513. X        } else
  1514. X            return (0);
  1515. X        }
  1516. X        /* break; Not Reached */
  1517. X      case CLOSE + 1:
  1518. X      case CLOSE + 2:
  1519. X      case CLOSE + 3:
  1520. X      case CLOSE + 4:
  1521. X      case CLOSE + 5:
  1522. X      case CLOSE + 6:
  1523. X      case CLOSE + 7:
  1524. X      case CLOSE + 8:
  1525. X      case CLOSE + 9:{
  1526. X        register int    no;
  1527. X        register char  *save;
  1528. X
  1529. X        no = OP(scan) - CLOSE;
  1530. X        save = reginput;
  1531. X
  1532. X        if (regmatch(next)) {
  1533. X            /*
  1534. X             * Don't set endp if some later invocation of the same
  1535. X             * parentheses already has. 
  1536. X             */
  1537. X            if (regendp[no] == NULL)
  1538. X            regendp[no] = save;
  1539. X            return (1);
  1540. X        } else
  1541. X            return (0);
  1542. X        }
  1543. X        /* break; Not Reached */
  1544. X      case BRANCH:{
  1545. X        register char  *save;
  1546. X
  1547. X        if (OP(next) != BRANCH)    /* No choice. */
  1548. X            next = OPERAND(scan);    /* Avoid recursion. */
  1549. X        else {
  1550. X            do {
  1551. X            save = reginput;
  1552. X            if (regmatch(OPERAND(scan)))
  1553. X                return (1);
  1554. X            reginput = save;
  1555. X            scan = regnext(scan);
  1556. X            } while (scan != NULL && OP(scan) == BRANCH);
  1557. X            return (0);
  1558. X            /* NOTREACHED */
  1559. X        }
  1560. X        }
  1561. X        break;
  1562. X      case STAR:
  1563. X      case PLUS:{
  1564. X        register char   nextch;
  1565. X        register int    no;
  1566. X        register char  *save;
  1567. X        register int    min;
  1568. X
  1569. X        /*
  1570. X         * Lookahead to avoid useless match attempts when we know
  1571. X         * what character comes next. 
  1572. X         */
  1573. X        nextch = '\0';
  1574. X        if (OP(next) == EXACTLY)
  1575. X            nextch = *OPERAND(next);
  1576. X        min = (OP(scan) == STAR) ? 0 : 1;
  1577. X        save = reginput;
  1578. X        no = regrepeat(OPERAND(scan));
  1579. X        while (no >= min) {
  1580. X            /* If it could work, try it. */
  1581. X            if (nextch == '\0' || *reginput == nextch)
  1582. X            if (regmatch(next))
  1583. X                return (1);
  1584. X            /* Couldn't or didn't -- back up. */
  1585. X            no--;
  1586. X            reginput = save + no;
  1587. X        }
  1588. X        return (0);
  1589. X        }
  1590. X        /* break; Not Reached */
  1591. X      case END:
  1592. X        return (1);        /* Success! */
  1593. X        /* break; Not Reached */
  1594. X      default:
  1595. X        regerror("memory corruption");
  1596. X        return (0);
  1597. X        /* break; Not Reached */
  1598. X    }
  1599. X
  1600. X    scan = next;
  1601. X    }
  1602. X
  1603. X    /*
  1604. X     * We get here only if there's trouble -- normally "case END" is the
  1605. X     * terminating point. 
  1606. X     */
  1607. X    regerror("corrupted pointers");
  1608. X    return (0);
  1609. X}
  1610. X
  1611. X/*
  1612. X - regrepeat - repeatedly match something simple, report how many
  1613. X */
  1614. Xstatic int
  1615. Xregrepeat(p)
  1616. X    char           *p;
  1617. X{
  1618. X    register int    count = 0;
  1619. X    register char  *scan;
  1620. X    register char  *opnd;
  1621. X
  1622. X    scan = reginput;
  1623. X    opnd = OPERAND(p);
  1624. X    switch (OP(p)) {
  1625. X      case ANY:
  1626. X    count = strlen(scan);
  1627. X    scan += count;
  1628. X    break;
  1629. X      case EXACTLY:
  1630. X    while (mkup(*opnd) == mkup(*scan)) {
  1631. X        count++;
  1632. X        scan++;
  1633. X    }
  1634. X    break;
  1635. X      case ANYOF:
  1636. X    while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1637. X        count++;
  1638. X        scan++;
  1639. X    }
  1640. X    break;
  1641. X      case ANYBUT:
  1642. X    while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1643. X        count++;
  1644. X        scan++;
  1645. X    }
  1646. X    break;
  1647. X      default:            /* Oh dear.  Called inappropriately. */
  1648. X    regerror("internal foulup");
  1649. X    count = 0;        /* Best compromise. */
  1650. X    break;
  1651. X    }
  1652. X    reginput = scan;
  1653. X
  1654. X    return (count);
  1655. X}
  1656. X
  1657. X/*
  1658. X - regnext - dig the "next" pointer out of a node
  1659. X */
  1660. Xstatic char    *
  1661. Xregnext(p)
  1662. X    register char  *p;
  1663. X{
  1664. X    register int    offset;
  1665. X
  1666. X    if (p == ®dummy)
  1667. X    return (NULL);
  1668. X
  1669. X    offset = NEXT(p);
  1670. X    if (offset == 0)
  1671. X    return (NULL);
  1672. X
  1673. X    if (OP(p) == BACK)
  1674. X    return (p - offset);
  1675. X    else
  1676. X    return (p + offset);
  1677. X}
  1678. X
  1679. X#ifdef DEBUG
  1680. X
  1681. XSTATIC char    *regprop();
  1682. X
  1683. X/*
  1684. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1685. X */
  1686. Xvoid
  1687. Xregdump(r)
  1688. X    regexp         *r;
  1689. X{
  1690. X    register char  *s;
  1691. X    register char   op = EXACTLY;    /* Arbitrary non-END op. */
  1692. X    register char  *next;
  1693. X    extern char    *strchr();
  1694. X
  1695. X
  1696. X    s = r->program + 1;
  1697. X    while (op != END) {        /* While that wasn't END last time... */
  1698. X    op = OP(s);
  1699. X    printf("%2d%s", s - r->program, regprop(s));    /* Where, what. */
  1700. X    next = regnext(s);
  1701. X    if (next == NULL)    /* Next ptr. */
  1702. X        printf("(0)");
  1703. X    else
  1704. X        printf("(%d)", (s - r->program) + (next - s));
  1705. X    s += 3;
  1706. X    if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1707. X        /* Literal string, where present. */
  1708. X        while (*s != '\0') {
  1709. X        putchar(*s);
  1710. X        s++;
  1711. X        }
  1712. X        s++;
  1713. X    }
  1714. X    putchar('\n');
  1715. X    }
  1716. X
  1717. X    /* Header fields of interest. */
  1718. X    if (r->regstart != '\0')
  1719. X    printf("start `%c' ", r->regstart);
  1720. X    if (r->reganch)
  1721. X    printf("anchored ");
  1722. X    if (r->regmust != NULL)
  1723. X    printf("must have \"%s\"", r->regmust);
  1724. X    printf("\n");
  1725. X}
  1726. X
  1727. X/*
  1728. X - regprop - printable representation of opcode
  1729. X */
  1730. Xstatic char    *
  1731. Xregprop(op)
  1732. X    char           *op;
  1733. X{
  1734. X    register char  *p;
  1735. X    static char     buf[50];
  1736. X
  1737. X    (void) strcpy(buf, ":");
  1738. X
  1739. X    switch (OP(op)) {
  1740. X      case BOL:
  1741. X    p = "BOL";
  1742. X    break;
  1743. X      case EOL:
  1744. X    p = "EOL";
  1745. X    break;
  1746. X      case ANY:
  1747. X    p = "ANY";
  1748. X    break;
  1749. X      case ANYOF:
  1750. X    p = "ANYOF";
  1751. X    break;
  1752. X      case ANYBUT:
  1753. X    p = "ANYBUT";
  1754. X    break;
  1755. X      case BRANCH:
  1756. X    p = "BRANCH";
  1757. X    break;
  1758. X      case EXACTLY:
  1759. X    p = "EXACTLY";
  1760. X    break;
  1761. X      case NOTHING:
  1762. X    p = "NOTHING";
  1763. X    break;
  1764. X      case BACK:
  1765. X    p = "BACK";
  1766. X    break;
  1767. X      case END:
  1768. X    p = "END";
  1769. X    break;
  1770. X      case OPEN + 1:
  1771. X      case OPEN + 2:
  1772. X      case OPEN + 3:
  1773. X      case OPEN + 4:
  1774. X      case OPEN + 5:
  1775. X      case OPEN + 6:
  1776. X      case OPEN + 7:
  1777. X      case OPEN + 8:
  1778. X      case OPEN + 9:
  1779. X    sprintf(buf + strlen(buf), "OPEN%d", OP(op) - OPEN);
  1780. X    p = NULL;
  1781. X    break;
  1782. X      case CLOSE + 1:
  1783. X      case CLOSE + 2:
  1784. X      case CLOSE + 3:
  1785. X      case CLOSE + 4:
  1786. X      case CLOSE + 5:
  1787. X      case CLOSE + 6:
  1788. X      case CLOSE + 7:
  1789. X      case CLOSE + 8:
  1790. X      case CLOSE + 9:
  1791. X    sprintf(buf + strlen(buf), "CLOSE%d", OP(op) - CLOSE);
  1792. X    p = NULL;
  1793. X    break;
  1794. X      case STAR:
  1795. X    p = "STAR";
  1796. X    break;
  1797. X      case PLUS:
  1798. X    p = "PLUS";
  1799. X    break;
  1800. X      default:
  1801. X    regerror("corrupted opcode");
  1802. X    break;
  1803. X    }
  1804. X    if (p != NULL)
  1805. X    (void) strcat(buf, p);
  1806. X    return (buf);
  1807. X}
  1808. X#endif
  1809. X
  1810. X/*
  1811. X * The following is provided for those people who do not have strcspn() in
  1812. X * their C libraries.  They should get off their butts and do something
  1813. X * about it; at least one public-domain implementation of those (highly
  1814. X * useful) string routines has been published on Usenet.
  1815. X */
  1816. X#ifdef STRCSPN
  1817. X/*
  1818. X * strcspn - find length of initial segment of s1 consisting entirely
  1819. X * of characters not from s2
  1820. X */
  1821. X
  1822. Xstatic int
  1823. Xstrcspn(s1, s2)
  1824. X    char           *s1;
  1825. X    char           *s2;
  1826. X{
  1827. X    register char  *scan1;
  1828. X    register char  *scan2;
  1829. X    register int    count;
  1830. X
  1831. X    count = 0;
  1832. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1833. X    for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1834. X        if (*scan1 == *scan2++)
  1835. X        return (count);
  1836. X    count++;
  1837. X    }
  1838. X    return (count);
  1839. X}
  1840. X#endif
  1841. X
  1842. Xint
  1843. Xcstrncmp(s1, s2, n)
  1844. X    char           *s1, *s2;
  1845. X    int             n;
  1846. X{
  1847. X    char           *p, *S1, *S2, *strsave();
  1848. X    int             rval;
  1849. X
  1850. X    if (!reg_ic)
  1851. X    return (strncmp(s1, s2, n));
  1852. X
  1853. X    S1 = strsave(s1);
  1854. X    S2 = strsave(s2);
  1855. X
  1856. X    for (p = S1; *p; p++)
  1857. X    if (islower(*p))
  1858. X        *p = toupper(*p);
  1859. X
  1860. X    for (p = S2; *p; p++)
  1861. X    if (islower(*p))
  1862. X        *p = toupper(*p);
  1863. X
  1864. X    rval = strncmp(S1, S2, n);
  1865. X
  1866. X    free(S1);
  1867. X    free(S2);
  1868. X
  1869. X    return rval;
  1870. X}
  1871. X
  1872. Xchar           *
  1873. Xcstrchr(s, c)
  1874. X    char           *s;
  1875. X    char            c;
  1876. X{
  1877. X    char           *p;
  1878. X
  1879. X    for (p = s; *p; p++) {
  1880. X    if (mkup(*p) == mkup(c))
  1881. X        return p;
  1882. X    }
  1883. X    return NULL;
  1884. X}
  1885. SHAR_EOF
  1886. echo "End of archive 4 (of 6)"
  1887. # if you want to concatenate archives, remove anything after this line
  1888. exit
  1889.